//lambda表达式
//是在调用或作为函数参数传递的位置处定义匿名函数对象的便捷方法。
//通常，lambda用于封装传递给算法或异步方法的几行代码

//格式:	[]()->returntype{}	
//	[]是捕获列表,里面装上下文中出现，lambda函数中所需要的变量，没有变量也要有一个[]，这是lambda函数引出符
//	[=]表示值传递方式捕获父作用域的所有变量（包括this）
//	[&]表示引用传递捕捉父作用域的所有变量（包括this）
// [&var]表示引用捕捉变量var

//	()里是参数列表,和普通函数参数列表相似，如果没有参数列表，()可以省略不写
    注意 ： 1.lambda函数不能有默认参数
            2.所有参数必须有参数名
            3.不支持可变参数

//{}是函数体

//->returntype是返回类型，->是后置的写法，可以不写编译器会自动推导，但可能推导不正确
auto sum_ = [](int x, int y)->int
{
    return x+y;
}

//lambda表达式不用单独在外面定义函数再调用，相当于一个一次性函数，也可以重复使用，需要保存。
#include<iostream>
using namespace std;
int main()
{
	auto f = [](int x, int y)
		{
			cout << x + y << endl;
		};
	f(10, 30);      //40
	return 0;
}








//function类似与c语言的函数指针，包含在头文件#include<functional>中。
//格式:  function<函数返回类型(参数类型列表)> 函数别名;		——此为定义语法
//			函数别名 =  函数名;			——此为初始化语法，也可像变量的定义和初始化一样写在一起
//function可用于保存普通函数，lambda表达式，成员函数

#include<iostream>
#include<functional>
using namespace std;

void printA(int a)
{
	cout << "a= " << a << endl;
}

class Foo
{
public:
	Foo(int num) : num_(num) {};	//相当于num_ = num（在成员函数中才能用）
	void print_add(int a) const		//加const表名这个成员函数不改变成员变量，对成员变量是只读
	{
		cout << num_ + a << endl;
	}
	int num_;
};

int main()
{
	//保存普通函数
	function<void(int a)> func1 = printA;
	auto f = printA;	//也可以用auto自动推导
	f(5);		//a= 5   
	func1(5);	//a= 5

	//保存lambda表达式
	function<void(int, int)> func2 = [](int a, int b)
		{
			cout << "a+b = " << a + b << endl;
		};
	func2(11, 4);	//a+b = 15

	//保存成员函数
	function<void(const Foo&, int)> test = &Foo::print_add;		//第一个参数类型是Foo，一定要加引用
	Foo foo(10);	///创建对象
	test(foo, 1);	//第一个变量是foo

	return 0;
}

//注意，function无法保存重载的成员函数，需要使用到bind才可以。








//bind函数	头文件#include<functional>
//可将bind函数看作是一个通用的函数适配器
//它接受一个可调用对象，生成一个新的可调用对象来“适应”原对象的参数列表。
//bind作用：不同的任务能传递不同的参数

#include<iostream>
#include<functional>
#include<string>
using namespace std;

class A
{
public:
	void fun_3(int a, int b)
	{
		cout << "func_3 print: a=" << a << ", b=" << b << endl;
	}
	void fun_4(string str, int b)
	{
		cout << "func_4 print: str" << str << ", b=" << b << endl;
	}
	void fun_4(int a, int b)
	{
		cout << "func_4 print: a=" << a << ", b=" << b << endl;
	}
};

void fun_1(int x, int y, int z)
{
	cout << "func_1 print : x=" << x << ", y=" << y << ", z=" << z << endl;
}

void fun_2(int &a, int &b)
{
	a++;
	b++;
	cout << "func_2 print : a=" << a << ", b=" << b <<  endl;
}

int main()
{
	//f1的类型为 function<void(int, int, int)>
	auto f1 = bind(fun_1, 1, 2, 3);
	f1();	
	f1(4, 5, 6);	//修改无效，bind已经绑定参数为1， 2， 3
	cout << "---------------------------------" << endl;

	//占位符
	auto f2 = bind(fun_1, placeholders::_1, placeholders::_2, 3);	//绑定第三个参数为3，_1位置输入为第一个参数， _2位置输入为第二个参数
	f2(11, 12);
	f2(11, 22, 33);	//第三个参数已被绑定
	cout << "---------------------------------" << endl;

	auto f3 = bind(fun_1, placeholders::_2, placeholders::_1, 3);	//绑定第三个参数为3，_2位置输入(即第一个输入位)为第二个参数， _1位置输入为第一个参数
	f3(11, 12);
	f3(11, 22, 33);	//第三个参数已被绑定，注意f2和f3的区别
	cout << "---------------------------------" << endl;

	//传入引用
	int a = 2, b = 3;
	auto f4 = bind(fun_2, placeholders::_1, b);
	f4(a);		
	cout << "main print:a=" << a << ", b=" << b << endl;	//bind对于不事先绑定的参数，即通过std::placeholders传 递的参数是通过引用传递的
	cout << "---------------------------------" << endl;	

	// 绑定成员函数
	A aa;
	auto f5 = bind(&A::fun_3, aa, placeholders::_1, placeholders::_2);	//必须引用A类
	f5(10, 20);
	// std::function<void(int,int)> fc = std::bind(&A::fun_3, a,std::placeholders::_1,std::placeholders::_2); 
	// fc(10,20); //调用a.fun_3,和上面的auto等价
	cout << "-----------------------------" << endl;

	// 重载函数
	auto my = bind((void(A::*)(string, int)) & A::fun_4, aa, placeholders::_1, 13);
	my("hello world");

	return 0;
}

/*
func_1 print : x=1, y=2, z=3
func_1 print : x=1, y=2, z=3
---------------------------------
func_1 print : x=11, y=12, z=3
func_1 print : x=11, y=22, z=3
---------------------------------
func_1 print : x=12, y=11, z=3
func_1 print : x=22, y=11, z=3
---------------------------------
func_2 print : a=3, b=4
main print:a=3, b=3
---------------------------------
func_3 print: a=10, b=20
-----------------------------
func_4 print: strhello world, b=13
*/